package com.candy.snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

/**
 * @author 
 * @date 2022-02-25 15:24:25
 */
// 集成一个面板JPanel
public class GamePanel extends JPanel implements KeyListener,ActionListener {
    // 蛇的长度
    int length;
    // 蛇的坐标x
    int[] snakeX = new int[600];
    // 蛇的坐标y
    int[] snakeY = new int[500];
    // 设置蛇的默认方向,R:右;L:左;U:上;D:下
    String fx;
    // 判断游戏是否开始
    boolean isStart = false;
    // 定时器
    Timer timer = new Timer(100,this);

    // 积分
    int score;
    // 模式
    String type = "";

    // 定义食物坐标
    int foodX;
    int foodY;
    Random random = new Random();

    // 死亡判断
    boolean isFail = false;

    // 构造器调用初始化方法
    public GamePanel(){
        init();
        // 获取键盘的监听事件
        this.setFocusable(true);
        this.addKeyListener(this);
        timer.start(); // 让时间动起来
    }

    // 初始化游戏
    public void init(){
        length = 3;
        // 头部坐标
        snakeX[0] = 93; snakeY[0] = 100;
        // 第一个身体坐标
        snakeX[1] = 68; snakeY[1] = 100;
        // 第二个身体坐标
        snakeX[2] = 43; snakeY[2] = 100;
        // 初始化方向为右
        fx = "R";

        foodX = 18 + 25 * random.nextInt(34);
        foodY = 75 + 25 * random.nextInt(24);

        score = 0;
    }


    // 画板:画界面、画蛇
    // Graphics:画笔
    @Override
    protected void paintComponent(Graphics g) {
        // 清屏
        super.paintComponent(g);
        // 设置背景图片
        this.setBackground(Color.WHITE);

        // 绘制头部广告栏
        Data.header.paintIcon(this,g,18,11);
        // 绘制游戏区域
        g.fillRect(18,75,850,600);

        // 画一条静态的小蛇
        if(fx.equals("R")){
            Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);
        } else if(fx.equals("L")){
            Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);
        } else if(fx.equals("U")){
            Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);
        } else if(fx.equals("D")){
            Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        for(int i = 1; i < length; i++){
            // 蛇的身体长度通过length来控制
            Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
        }

        // 画食物
        Data.food.paintIcon(this,g,foodX,foodY);

        // 画积分
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,18));
        g.drawString("长度："+length,750,32);
        g.drawString("分数："+score,750,53);

        // 选择游戏模式
        if("".equals(type)){
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑",Font.BOLD,26));
            g.drawString("  F1:无尽模式",350,300);
            g.drawString("  F2:挑战模式",350,350);
            g.drawString("ESC:返回主界面",350,400);
        }

        // 游戏提示:是否开始
        if(isStart == false && !"".equals(type)){
            // 画一个文字
            g.setColor(Color.white); // 设置画笔颜色
            g.setFont(new Font("微软雅黑",Font.BOLD,40)); // 设置字体
            g.drawString("按下空格开始游戏",300,300);
        }

        // 失败提醒
        if(isFail && !"".equals(type)){
            // 画一个文字
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("游戏失败，按下空格重新开始",200,300);
        }
    }

    // 接收键盘的输入:键盘按下未释放
    @Override
    public void keyPressed(KeyEvent e) {
        // 获取按下的键盘是哪个键
        int keyCode = e.getKeyCode();
        if(keyCode == KeyEvent.VK_F1){ // 如果按下F1则是无尽模式
            type = "F1";
            repaint();
        } else if(keyCode == KeyEvent.VK_F2){ // 如果按下F2则是挑战模式
            type = "F2";
            repaint();
        }

        if(keyCode == KeyEvent.VK_ESCAPE){ // 如果按下ESC则返回主界面
            type = "";
            isFail = false;
            isStart = false;
            init();
            repaint();
        }

        if(keyCode == KeyEvent.VK_SPACE){ // 如果按下的空格键,就刷新界面
            if(isFail){// 如果游戏失败,从头再来
                isFail = false;
                init();
            } else {// 否则暂停游戏
                isStart = !isStart;
            }
            repaint();
        }

        // 键盘控制走向,且不能掉头
        if(keyCode == KeyEvent.VK_LEFT && !fx.equals("R")){
            fx = "L";
        } else if(keyCode == KeyEvent.VK_RIGHT && !fx.equals("L")){
            fx = "R";
        } else if(keyCode == KeyEvent.VK_UP && !fx.equals("D")){
            fx = "U";
        } else if(keyCode == KeyEvent.VK_DOWN && !fx.equals("U")){
            fx = "D";
        }
    }

    // 定时器,鉴定时间,执行定时操作
    @Override
    public void actionPerformed(ActionEvent e) {
        // 如果游戏处于开始状态,并且游戏没有结束,并且是无尽模式
        if(isStart && isFail==false && type.equals("F1")){
            // 右移
            move();
            // 通过控制方向让头部移动
            if(fx.equals("R")){
                snakeX[0] = snakeX[0] + 25; // 头部移动
                if(snakeX[0] > 843){ // 边界判断
                    snakeX[0] = 18;
                }
            } else if (fx.equals("L")){
                snakeX[0] = snakeX[0] - 25;
                if(snakeX[0] < 18){
                    snakeX[0] = 843;
                }
            } else if (fx.equals("U")){
                snakeY[0] = snakeY[0] - 25;
                if(snakeY[0] < 75){
                    snakeY[0] = 650;
                }
            } else if (fx.equals("D")){
                snakeY[0] = snakeY[0] + 25;
                if(snakeY[0] > 650){
                    snakeY[0] = 75;
                }
            }

            // 如果头和食物坐标重合则吃到食物了
            eat();

            // 结束判断
            over();

            // 刷新界面
            repaint();
        }


        // 如果游戏处于开始状态,并且游戏没有结束,并且是挑战模式
        if(isStart && isFail==false && type.equals("F2")){
            // 右移
            move();
            // 通过控制方向让头部移动
            if(fx.equals("R")){
                snakeX[0] = snakeX[0] + 25; // 头部移动
                if(snakeX[0] > 843){ // 边界判断
                    isFail = true;
                }
            } else if (fx.equals("L")){
                snakeX[0] = snakeX[0] - 25;
                if(snakeX[0] < 18){
                    isFail = true;
                }
            } else if (fx.equals("U")){
                snakeY[0] = snakeY[0] - 25;
                if(snakeY[0] < 75){
                    isFail = true;
                }
            } else if (fx.equals("D")){
                snakeY[0] = snakeY[0] + 25;
                if(snakeY[0] > 650){
                    isFail = true;
                }
            }

            // 如果头和食物坐标重合则吃到食物了
            eat();

            // 结束判断
            over();

            // 刷新界面
            repaint();
        }
        timer.start(); // 让时间动起来
    }

    // 身体移动
    private void move(){
        for(int i = length - 1;i > 0;i--){// 除了脑袋,身体都向前移动
            snakeX[i] = snakeX[i-1];
            snakeY[i] = snakeY[i-1];
        }
    }

    // 如果头和食物坐标重合则吃到食物了
    private void eat(){
        if(snakeX[0] == foodX && snakeY[0] == foodY){
            length++;
            score += 10;
            snakeX[length-1] = snakeX[length-2] * 2 - snakeX[length-3];
            snakeY[length-1] = snakeY[length-2] * 2 - snakeY[length-3];
            // 重新生成食物
            foodX = 18 + 25 * random.nextInt(34);
            foodY = 75 + 25 * random.nextInt(24);
        }
    }

    // 结束判断
    private void over(){
        for (int i = 1;i < length;i++){
            // 如果头和身体碰撞,说明游戏失败
            if(snakeX[i] == snakeX[0] && snakeY[i] == snakeY[0]){
                isFail = true;
            }
        }
    }

    // 定时器,监听时间
    // 接收键盘的输入:键盘按下弹起
    @Override
    public void keyTyped(KeyEvent e) {

    }
    // 接收键盘的输入:键盘释放
    @Override
    public void keyReleased(KeyEvent e) {

    }
}
